﻿using SimWithP3d.Vehicle;
using LockheedMartin.Prepar3D.SimConnect;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SimWithP3d.Vehicle
{
    public class SimC172R : SimControlAircraft
    {
        public SimC172R() : base()
        {
            InitEVENTS();
            InitDatas();
        }
        #region 初始事件相关
        /// <summary>
        /// 自动驾驶相关事件
        /// </summary>
        private enum EVENTS
        {
            //自动驾驶相关
            AP_MASTER,//打开/关闭AP
            AP_HDG_HOLD,//航向模式
            AP_NAV1_HOLD,//导航模式
            AP_APR_HOLD,// 逼近模式
            AP_BC_HOLD,//后退进场模式REV
            AP_ALT_HOLD,//高度保持模式
            AP_ALT_VAR_INC,//增加参考高度
            AP_ALT_VAR_DEC,//减少参考高度
            AP_VS_VAR_INC, //增加垂直速度参考
            AP_VS_VAR_DEC//	递减垂直速度参考
        };
        /// <summary>
        /// 通知组
        /// </summary>
        private enum NOTIFICATION_GROUPS
        {
            GROUP0,
        }
        /// <summary>
        /// 初始事件相关
        /// </summary>
        private void InitEVENTS()
        {
            try
            {
                #region 自动驾驶相关事件
                simConnect.MapClientEventToSimEvent(EVENTS.AP_MASTER, "AP_MASTER");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_MASTER, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_HDG_HOLD, "AP_HDG_HOLD");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_HDG_HOLD, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_NAV1_HOLD, "AP_NAV1_HOLD");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_NAV1_HOLD, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_APR_HOLD, "AP_APR_HOLD");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_APR_HOLD, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_BC_HOLD, "AP_BC_HOLD");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_BC_HOLD, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_ALT_HOLD, "AP_ALT_HOLD");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_ALT_HOLD, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_ALT_VAR_INC, "AP_ALT_VAR_INC");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_ALT_VAR_INC, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_ALT_VAR_DEC, "AP_ALT_VAR_DEC");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_ALT_VAR_DEC, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_VS_VAR_INC, "AP_VS_VAR_INC");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_VS_VAR_INC, false);
                simConnect.MapClientEventToSimEvent(EVENTS.AP_VS_VAR_DEC, "AP_VS_VAR_DEC");
                simConnect.AddClientEventToNotificationGroup(NOTIFICATION_GROUPS.GROUP0, EVENTS.AP_VS_VAR_DEC, false);
                #endregion
            }
            catch (COMException ex)
            {
                Console.WriteLine("Connect => Unable to connect to Prepar3D:\n" + ex.Message);
            }
        }      
        /// <summary>
        /// 处理下位机消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="recEvent"></param>
        public void Simconnect_TransmitClientEvent(string type)
        {
            switch (type)
            {
                case "AP_MASTER":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_MASTER, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_HDG_HOLD":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_HDG_HOLD, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_NAV1_HOLD":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_NAV1_HOLD, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_APR_HOLD":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_APR_HOLD, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_BC_HOLD":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_APR_HOLD, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_ALT_HOLD":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_ALT_HOLD, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_ALT_VAR_INC":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_ALT_VAR_INC, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_ALT_VAR_DEC":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_ALT_VAR_DEC, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_VS_VAR_INC":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_VS_VAR_INC, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
                case "AP_VS_VAR_DEC":
                    simConnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, EVENTS.AP_VS_VAR_DEC, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                    break;
            }
        }
        #endregion
        #region 请求数据
        AutopilotVariables autopilotVariables;
        enum DEFINITIONS
        {
            AutopilotVariables,
        }
        enum DATA_REQUESTS
        {
            REQUEST_AutoPilot,
        };
        struct AutopilotVariables
        {
            public bool master;
            public bool headingLock;
            public bool nav1lock;
            public bool approachHold;
            public bool backcourseHold;
        };
        /// <summary>
        /// 初始自动驾驶数据相关
        /// </summary>
        private void InitDatas()
        {
            try
            {
                #region 自动驾驶相关数据
                simConnect.AddToDataDefinition(DEFINITIONS.AutopilotVariables, "AUTOPILOT MASTER", "Bool", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                simConnect.AddToDataDefinition(DEFINITIONS.AutopilotVariables, "AUTOPILOT HEADING LOCK", "Bool", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                simConnect.AddToDataDefinition(DEFINITIONS.AutopilotVariables, "AUTOPILOT NAV1 LOCK", "Bool", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                simConnect.AddToDataDefinition(DEFINITIONS.AutopilotVariables, "AUTOPILOT APPROACH HOLD", "Bool", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                simConnect.AddToDataDefinition(DEFINITIONS.AutopilotVariables, "AUTOPILOT BACKCOURSE HOLD", "Bool", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                #endregion
                simConnect.RegisterDataDefineStruct<AutopilotVariables>(DEFINITIONS.AutopilotVariables);
                // catch a simobject data request
                simConnect.OnRecvSimobjectDataBytype += new SimConnect.RecvSimobjectDataBytypeEventHandler(simConnect_OnRecvSimobjectDataBytype);
            }
            catch (COMException ex)
            {
                Console.WriteLine("Connect => Unable to connect to Prepar3D:\n" + ex.Message);
            }
        }
        private void simConnect_OnRecvSimobjectDataBytype(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE data)
        {
            switch ((DATA_REQUESTS)data.dwRequestID)
            {
                case DATA_REQUESTS.REQUEST_AutoPilot:
                    autopilotVariables = (AutopilotVariables)data.dwData[0];
                    break;
                default:
                    break;
            }
        }
        public void GetAutopilotVariables()
        {
            simConnect.RequestDataOnSimObjectType(DATA_REQUESTS.REQUEST_AutoPilot, DEFINITIONS.AutopilotVariables, 0, SIMCONNECT_SIMOBJECT_TYPE.USER);
        }
        #endregion
    }
}
